using AutoMapper;
using MD5Hash;
using MediatR;
using S.O.Domain.RBAC;
using S.O.Domain.Dto.Output;
using S.O.ErrorCode;
using S.O.Interstructrue.Base;
using S.O.Api.Read.Application.Command.User.Login;

namespace S.O.Api.Read.Application.Handler.User.Login
{
    /// <summary>
    /// 用户登录处理器
    /// 负责处理用户登录验证的业务逻辑，包括用户名密码验证、角色信息获取等
    /// </summary>
    public class LoginHandler : IRequestHandler<LoginCommand, APIResult<UserDto>>
    {
        /// <summary>
        /// 用户仓储接口，用于用户数据的查询操作
        /// </summary>
        private readonly IBaseRepository<UserModel> userRepository;
        
        /// <summary>
        /// 角色仓储接口，用于角色数据的查询操作
        /// </summary>
        private readonly IBaseRepository<RoleModel> roleRepository;
        
        /// <summary>
        /// 用户角色关联仓储接口，用于查询用户和角色的关联关系
        /// </summary>
        private readonly IBaseRepository<UserRoleModel> userreoleRepository;
        
        /// <summary>
        /// 对象映射器，用于Model对象到DTO对象的转换
        /// </summary>
        private readonly IMapper mapper;
        
        /// <summary>
        /// 日志记录器，用于记录操作日志和错误信息
        /// </summary>
        private readonly ILogger<LoginHandler> logger;

        /// <summary>
        /// 构造函数，通过依赖注入初始化所需的服务
        /// </summary>
        /// <param name="userRepository">用户仓储服务</param>
        /// <param name="roleRepository">角色仓储服务</param>
        /// <param name="userreoleRepository">用户角色关联仓储服务</param>
        /// <param name="mapper">对象映射服务</param>
        /// <param name="logger">日志记录服务</param>
        public LoginHandler(IBaseRepository<UserModel> userRepository, IBaseRepository<RoleModel> roleRepository, IBaseRepository<UserRoleModel> userreoleRepository, IMapper mapper, ILogger<LoginHandler> logger)
        {
            this.userRepository = userRepository;
            this.roleRepository = roleRepository;
            this.userreoleRepository = userreoleRepository;
            this.mapper = mapper;
            this.logger = logger;
        }
        
        /// <summary>
        /// 处理用户登录命令
        /// 验证用户名和密码，获取用户角色信息，返回登录结果
        /// </summary>
        /// <param name="request">登录命令对象，包含用户名和密码</param>
        /// <param name="cancellationToken">取消令牌，用于取消异步操作</param>
        /// <returns>返回包含用户信息和角色信息的APIResult对象</returns>
        public Task<APIResult<UserDto>> Handle(LoginCommand request, CancellationToken cancellationToken)
        {
            // 初始化返回结果对象
            APIResult<UserDto> res = new APIResult<UserDto>();
            
            // 对用户输入的密码进行MD5加密
            var pwd = request.Password.GetMD5();
            
            // 根据用户名和加密后的密码查找用户
            var user = userRepository.GetALL().FirstOrDefault(x => x.UserName == request.UserName && x.Password == pwd);
            
            // 验证用户是否存在
            if (user == null)
            {
                res.Code = APIEnums.Error;
                res.Msg = "用户名或密码错误";
                logger.LogError($"登录失败：用户名{request.UserName}不存在或密码错误");
                return Task.FromResult(res);
            }
            
            // 查找用户的角色关联信息
            var userrole = userreoleRepository.GetALL().FirstOrDefault(x => x.UserId == user.Id);
            if (userrole == null)
            {
                res.Code = APIEnums.Error;
                res.Msg = "系统未为用户分配角色";
                res.Data = null;
                logger.LogError($"用户{user.UserName}未分配角色");
                return Task.FromResult(res);
            }
            
            // 根据角色ID获取角色详细信息
            var role = roleRepository.GetModel(userrole.RoleId);
            if (role == null)
            {
                res.Code = APIEnums.Error;
                res.Msg = "用户角色不存在";
                res.Data = null;
                logger.LogError($"用户{user.UserName}的角色ID{userrole.RoleId}不存在");
                return Task.FromResult(res);
            }
            
            // 使用AutoMapper将用户实体映射为DTO对象
            var data = mapper.Map<UserDto>(user);
            
            // 设置角色相关信息
            data.RoleName = role.RoleName;
            data.RoleId = role.Id;
            
            // 设置成功返回结果
            res.Code = APIEnums.Success;
            res.Data = data;
            res.Msg = "用户登录成功";
            
            // 记录登录成功日志
            logger.LogInformation($"用户{user.UserName}登录成功，角色：{role.RoleName}");
            
            return Task.FromResult(res);
        }
    }
}
